using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace Ramparts
{
    // Scenemanager is responsible for loading and unloading scenes
    // It also keeps game assets that are common across all scenes
    // along with having a tile engine to display tiled world data
    public class SceneManager
    {
        public GameTime gameTime;

        // Our Index Of Scenes That The Scenemanager can load
        public enum SCENES { MAIN_MENU=0, BATTLE_SCENE, PLACE_CANNONS, BUILD, CREDITS, LEVEL_EDITOR};
        
        // Rampart keeps a reference to the Game Object
        public Ramparts rampart;

        // The currently loaded scene. This could be changed to a stack
        public Scene currentScene;
        public Stack<Scene> scenes;
        
        // Game world represents the tiled artwork in the game
        public World world;

        // Audio stuff
        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;
        Cue backgroundMusic = null;
        AudioCategory musicCategory;
        public float backgroundMusicVolume = .01f;
        public float effectsVolume = .01f;

        // Font to use for debug
        SpriteFont debugFont;
     
        // Constructor that takes a Ramparts object
        // Initializes all necessary variables
        public SceneManager(Ramparts game)
        {
            rampart = game;
        }

        public void pushScene(Scene scene)
        {
            scenes.Push(scene);
            currentScene = scene;
        }
        
        // Initialize the scenemanager to the indicated scene
        // pass the number on the command line as the first arg to the program
        public void initSceneManager(int sceneIndex)
        {

            scenes = new Stack<Scene>();
            
            debugFont = rampart.Content.Load<SpriteFont>("Content\\Fonts\\CourierNew");

            world = new World(rampart,"Content\\Levels\\Map0.map");
            
            switch ((SCENES)sceneIndex)
            {
                case SCENES.MAIN_MENU:
                    pushScene(new MainMenu(this));
                    break;
                case SCENES.BUILD:
                    pushScene(new BuildPhase(this));
                    break;
                case SCENES.LEVEL_EDITOR:
        //            pushScene(new LevelEditor(this));
                    break;
                default:
                    pushScene(new MainMenu(this));
                    break;
            }



            // init Audio
            audioEngine = new AudioEngine("Content\\Audio\\RampartsAudio.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Audio\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Audio\\Sound Bank.xsb");

            // Start Background Music
            audioEngine.GetCategory("Music").SetVolume(backgroundMusicVolume);
            backgroundMusic = soundBank.GetCue("game_background");
            backgroundMusic.Play();

            backgroundMusicVolume = .01f;
            scenes.Peek().initScene();
        }

    
        

        // Process event just passes event information down to the 
        // current scene for processing
        // Since we are storing the music volume here i am going to make
        // the changes here
        public void Update(GameTime gameTime)
        {
            audioEngine.GetCategory("Music").SetVolume(backgroundMusicVolume);
            scenes.Peek().Update(gameTime);
            

        }

        // Eventually will load a scene from a file if necessary.
        // a scene could be an XML file with the layout of the level
        // for now it fake populates the tile map
        public bool loadSceneFromFile()
        {
            scenes.Peek().initScene();
            return true;
        }

        // Draw the current scene, passes this down to the scene to handle this
        public void DrawScene()
        {
            
            scenes.Peek().drawScene();
            
            
        }

        /// <summary>
        /// Uses a pair of keys to simulate a positive or negative axis input.
        /// </summary>
        public float ReadKeyboardAxis(KeyboardState keyState, Keys downKey,
                                              Keys upKey)
        {
            float value = 0;

            if (keyState.IsKeyDown(downKey))
                value -= 1.0f;

            if (keyState.IsKeyDown(upKey))
                value += 1.0f;

            return value;
        }

        public void drawWorldDebug()
        {

            Vector2 debugPosition = new Vector2(100, 400);
            MouseState current_mouse = Mouse.GetState();

            // The mouse x and y positions are returned relative to the
            // upper-left corner of the game window.
            int mouseX = current_mouse.X;
            int mouseY = current_mouse.Y;

            // Find the center of the string
            String output = "Mouse: " + current_mouse.X + "/" + current_mouse.Y;

            Vector2 FontOrigin = debugFont.MeasureString(output) / 2;
            // Draw the string
            rampart.spriteBatch.DrawString(debugFont, output, debugPosition, Color.Red,
                0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);

                output = "Camera: " + currentScene.camera.Position.X + "/" + currentScene.camera.Position.Y;
                debugPosition.Y = debugPosition.Y + 25;
                FontOrigin = debugFont.MeasureString(output) / 2;
                rampart.spriteBatch.DrawString(debugFont, output, debugPosition, Color.Red,
                    0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);

                Vector2 onTile = world.groundLayer.onTile(new Vector2(current_mouse.X, current_mouse.Y));
                output = "Ground Tile: " + onTile.X + "/" + onTile.Y;
                debugPosition.Y = debugPosition.Y + 25;
                FontOrigin = debugFont.MeasureString(output) / 2;
                rampart.spriteBatch.DrawString(debugFont, output, debugPosition, Color.Red,
                    0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);

                Vector2 transPos = world.buildingLayer.onTile(new Vector2(current_mouse.X, current_mouse.Y));
                output = "Building Tile: " + transPos.X + "/" + transPos.Y;
                debugPosition.Y = debugPosition.Y + 25;
                FontOrigin = debugFont.MeasureString(output) / 2;
                rampart.spriteBatch.DrawString(debugFont, output, debugPosition, Color.Red,
                            0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
     
        }

        /// <summary>
        /// This will add a new scene on top of the stack.  Initialize it and pass it in.
        /// </summary>
        /// <param name="newScene"></param>
        public void AddScene(Scene newScene)
        {
            scenes.Push(newScene);
        }

        /// <summary>
        /// This will pop a scene off as long as it isn't the last scene in the stack
        /// </summary>
        /// <returns></returns>
        public bool RemoveScene()
        {
            if (scenes.Count < 2)
            {
                return false;
            }
            else
            {
                scenes.Pop();
                return true;
            }
        }

        /// <summary>
        /// This will remove the scene on the top of the stack and load in the passed one.
        /// Make sure this scene is initalized before passing it in
        /// </summary>
        /// <param name="newScene"></param>
        public void SwapScenes(Scene newScene)
        {
            scenes.Pop();
            scenes.Push(newScene);
        }

    } // end Class
} // end Namespace
